import 'dart:convert';

import 'package:dio/dio.dart' as DIO;
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:sgy_flutter/model/update_info.dart';

import 'model/hitch_fix_model.dart';
import 'model/hitch_record_req.dart';

class ApiService extends GetxService {
  late DIO.Dio _dio;

  static const baseURL = "http://43.136.96.139:8521/";

  DIO.Dio get downloadDio => DIO.Dio(
      DIO.BaseOptions(
        baseUrl: baseURL,
        receiveTimeout: Duration(minutes: 5),
        sendTimeout: Duration(minutes: 1)
      )
  ) ..interceptors
      .add(PrettyDioLogger(requestHeader: true, requestBody: true));

  @override
  void onInit() {
    FlutterBluePlus.setLogLevel(LogLevel.debug);
    _dio = DIO.Dio(
      DIO.BaseOptions()
        // ..baseUrl = "https://app.sigeyi.com/sgy/admin/api/"
        ..baseUrl = baseURL,
    )
      ..interceptors.add(LangInterceptor())
      ..interceptors
          .add(PrettyDioLogger(requestHeader: true, requestBody: true));
    super.onInit();
  }

  /**
   * 未找到我的设备
   */
  Future<Resp<String>> getHelp() async {
    return await _transformation(
        _dio.get("api/sgy/sysset/getHelp"),
            (data) => data);
  }

  /**
   * 问题帮助
   */
  Future<Resp<String>> getQuestion(String deviceType) async {
    return await _transformation(
        _dio.get("api/sgy/sysset/getQuestion?deviceType=$deviceType"),
        (data) => data);
  }

  Future<Resp<bool>> checkBlacklist(
      {required String deviceName, required String deviceSN}) async {
    return await _transformation(
        _dio.get("api/sgy/blacklist/check", queryParameters: {
          "deviceId": deviceSN,
          "deviceName": deviceName,
        }),
        (value) => value);
  }

  Future<Resp<String>> getFallbackVersion({
    required String hardwareVersion,
    required String firmwareVersion,
    bool newVersion = false,
  }) async {
    return await _transformation(
        _dio.get("api/sgy/firmware/getFallbackVersion", queryParameters: {
          "hardwareVersion": hardwareVersion,
          "currentVersion": firmwareVersion,
          "newVersion": newVersion,
        }),
        (value) => value);
  }

  /**
   * 获取固件升级版本
   */
  Future<Resp<UpdateInfoModel>> getFirmwareVersion(
      String hardwareVersion) async {
    return await _transformation(
        _dio.get("api/sgy/firmware/getNewestFirmwareVersion", queryParameters: {
          "hardwareVersion": hardwareVersion,
        }),
        UpdateInfoModel.fromMap);
  }

  /**
   * 获取固件升级版本
   * 老的
   */
  Future<Resp<UpdateInfoModel>> getFirmwareVersionOld({
    required String deviceType,
    required String firmwareVersion,
    bool newVersion = false,
  }) async {
    return await _transformation(
        _dio.get("api/sgy/firmware/getNextVision", queryParameters: {
          "deviceType": deviceType,
          "currentVision": firmwareVersion,
          "newVersion": newVersion,
        }),
        UpdateInfoModel.fromMap);
  }

  /**
   * 回退上个版本
   */
  // @GET("api/sgy/firmware/getPackageUrl")
  Future<Resp<String>> getFallbackVersionOld({
    required String deviceType,
    required String firmwareVersion,
    bool newVersion = false,
  }) async {
    return await _transformation(
        _dio.get("api/sgy/firmware/getPackageUrl", queryParameters: {
          "deviceType": deviceType,
          "currentVision": firmwareVersion,
          "newVersion": newVersion,
        }),
        (value) => value);
  }

  Future<Resp<bool>> fixHitch({
    required String? id,
  }) async {
    return await _transformation(
        _dio.get("api/sgy/hitch/fix", queryParameters: {
          "id": id
        }),
        (value) => value);
  }


  Future<Resp<HitchFixModel>> checkHitch({
    required String? productSn,
    required String? deviceId,
  }) async {
    return await _transformation(
        _dio.get("api/sgy/hitch/check", queryParameters: {
          "productSn": productSn,
          "deviceId": deviceId,
        }),
        HitchFixModel.fromMap);
  }


    Future<Resp<bool>> uploadHitchRecord({
      required HitchRecordReq req,
    }) async {
      return await _transformation(
          _dio.post("api/sgy/hitch/record", data: req.toMap()),
          (value) => value);
  }

  Future<Resp<T>> _transformation<T>(
      Future<DIO.Response> future, T? Function(dynamic data) fmt) async {
    try {
      return await future.then((value) => Resp.fromResp(value, fmt));
    } on DIO.DioException catch (error) {
      if (error.response?.data != null) {
        if (error.response?.data is Map) {
          var resp = Resp<T>.fromJson(error.response?.data);
          if (resp.code == 401) {
            rethrow;
          }
          return resp;
        }
      }
      rethrow;
    }
  }
}

class Resp<T> {
  final int code;
  final String message;
  final T? data;

  Resp({required this.code, required this.message, this.data});

  bool get isSuccess => code == 0;

  factory Resp.fromJson(Map<String, dynamic> json) {
    return Resp(
      code: json['code'].runtimeType == String
          ? int.parse(json['code'])
          : json['code'],
      message: json['msg'],
      data: json['data'],
    );
  }

  factory Resp.fromResp(DIO.Response response, T? Function(dynamic data) fmt) {
    var data = response.data;
    var json = data is Map ? data : jsonDecode(data);

    var code = json['code'].runtimeType == String
        ? int.parse(json['code'])
        : json['code'];
    if (code == 0) {
      return Resp(
        code: code,
        message: json['msg'],
        data: fmt(json['data']),
      );
    } else {
      throw RespError(
          resp: Resp(
        code: code,
        message: json['msg'],
        data: json['data'],
      ));
    }
  }

  @override
  String toString() {
    return 'Resp{code: $code, message: $message, data: ${data.toString()}';
  }
}

class RespError extends Error {
  final Resp? resp;

  RespError({required this.resp});
}

class LangInterceptor extends DIO.Interceptor {
  @override
  void onRequest(
      DIO.RequestOptions options, DIO.RequestInterceptorHandler handler) {
    options.queryParameters['lang'] = Get.locale?.languageCode;
    super.onRequest(options, handler);
  }
}
